//
// Created by QU on 2023/8/21.
//

#include <stdlib.h>
#include <memory.h>

#include "paramPasser.h"
#include "dataGenerator.h"
#include "utils.h"


/**
 * 向块中全零填充.
 * @param mallocBuffer
 * @param filledSize
 * @return 已经填充的字节数
 */
size_t fillBlockWithZero(uint8_t *mallocBuffer, size_t filledSize) {
    if (mallocBuffer == NULL || filledSize <= 0) {
        printErrorMessage("Parameter Illegal");
        exit(EXIT_FAILURE);
    }

    memset(mallocBuffer, 0x00, filledSize);
    return filledSize;
}


/**
 * 下面是generate系列函数, 函数应当满足这样的要求:
 * 接受一个数据块和他的长度, 向内填充数据内容, 接受一个(可以更改数据的)位置下标指针,
 * 下一次调用函数的时候通过指针指向的数据能够继续向这个块生成数据.
 */

/**
 * generate系列函数, 用于向已分配块中生成可连续的数据
 * @param mallocBuffer 已开辟的空间
 * @param mallocBufferSize 填充长度, 应该填入mallocBuffer的长度
 * @param continueIndex 一个生成数据进度的字节下标, 第一次传入的值应该是0, 当然你也可以通过传入字节位置继续生成.
 * @return 已经填充的字节数
 */
size_t generateData_60a1da8e(uint8_t *mallocBuffer, size_t mallocBufferSize, size_t *continueIndex) {
    if (mallocBuffer == NULL || mallocBufferSize <= 0) {
        printErrorMessage("Parameter Illegal");
        exit(EXIT_FAILURE);
    }

    // little endian
    uint8_t specificBlock[4] = {0x8E, 0xDA, 0xA1, 0x60};

    // 第一次传入的是0, 第二次是2340 * frameLen或者136 * frameLen
    size_t currIndex = (*continueIndex) % mallocBufferSize;

    size_t counter = 0;
    for (int i = 0; i < mallocBufferSize; ++i) {
        mallocBuffer[i] = specificBlock[currIndex % sizeof(specificBlock)];
        currIndex++;
        (*continueIndex)++;
        counter++;
    }

    return counter;
}

/**
 * generate系列函数, 用于向已分配块中生成可连续的数据
 * @param mallocBuffer 已开辟的空间
 * @param mallocBufferSize 填充长度, 应该填入mallocBuffer的长度
 * @param continueIndex 一个生成数据进度的字节下标, 第一次传入的值应该是0, 当然你也可以通过传入字节位置继续生成.
 * @return 已经填充的字节数
 */
size_t generateData_00toFF(uint8_t *mallocBuffer, size_t mallocBufferSize, size_t *continueIndex) {
    if (mallocBuffer == NULL || mallocBufferSize <= 0) {
        printErrorMessage("Parameter Illegal");
        exit(EXIT_FAILURE);
    }

    uint8_t currData = (*continueIndex) % (UINT8_MAX + 1);
    size_t counter = 0;

    while (counter < mallocBufferSize) {
        mallocBuffer[counter] = currData;
        currData++;
        (*continueIndex)++;
        counter++;
    }
    return counter;
}

/**
 * generate系列函数, 用于向已分配块中生成可连续的数据
 * @param mallocBuffer 已开辟的空间
 * @param filledSize 填充长度, 应该填入mallocBuffer的长度
 * @param continueIndex 一个生成数据进度的字节下标, 第一次传入的值应该是0, 当然你也可以通过传入字节位置继续生成.
 * @param logicalID 逻辑ID号, 传入一个固定值
 * @return 已经填充的字节数
 */
size_t
generateData_ChannelIncrement(uint8_t *mallocBuffer, size_t filledSize, size_t *continueIndex, uint16_t logicalID) {
    if (mallocBuffer == NULL || filledSize <= 0) {
        printErrorMessage("Parameter Illegal");
        exit(EXIT_FAILURE);
    }

    size_t currFilledSize = 0;

    uint32_t pattern = (uint32_t) (*continueIndex);           // 4 bytes;
    // 如果整除4字节的部分
    for (size_t i = 0; i < filledSize; i += 4) {
        // Store in Little Endian
        mallocBuffer[i] = (uint8_t) (pattern & 0xFF);
        currFilledSize++;
        mallocBuffer[i + 1] = (uint8_t) ((pattern >> 8) & 0xFF);
        currFilledSize++;
        mallocBuffer[i + 2] = (uint8_t) ((pattern >> 16) & 0xFF);
        currFilledSize++;
        mallocBuffer[i + 3] = (uint8_t) ((pattern >> 24) & 0xFF);
        currFilledSize++;
        (*continueIndex) += logicalID;
        pattern += logicalID;
    }

    return currFilledSize;
}


/**
 * generate系列函数, 用于向已分配块中生成可连续的数据
 * @param mallocBuffer 已开辟的空间
 * @param mallocBufferSize 填充长度, 应该填入mallocBuffer的长度
 * @param continueIndex 一个生成数据进度的字节下标, 第一次传入的值应该是0, 当然你也可以通过传入字节位置继续生成.
 * @param logicalID 逻辑ID号, 传入一个固定值
 * @return 已经填充的字节数
 */
size_t generateData_LowerIncrementHigherLogicalID(uint8_t *mallocBuffer, size_t mallocBufferSize, size_t *continueIndex,
                                                  uint16_t logicalID) {
    if (mallocBuffer == NULL || mallocBufferSize <= 0) {
        printErrorMessage("Parameter Illegal");
        exit(EXIT_FAILURE);
    }

    size_t currFilledSize = 0;

    uint16_t lowerBytes = (uint16_t) (*continueIndex);
    uint16_t higherBytes = logicalID;
    // 如果整除4字节的部分
    for (size_t i = 0; i < mallocBufferSize; i += 4) {

        // Store in Little Endian
        mallocBuffer[i] = (uint8_t) (lowerBytes & 0xFF);
        currFilledSize++;
        mallocBuffer[i + 1] = (uint8_t) ((lowerBytes >> 8) & 0xFF);
        currFilledSize++;
        mallocBuffer[i + 2] = (uint8_t) (higherBytes & 0xFF);
        currFilledSize++;
        mallocBuffer[i + 3] = (uint8_t) ((higherBytes >> 8) & 0xFF);

        lowerBytes++;
        (*continueIndex)++;
        currFilledSize++;
    }

    // 后续不足4字节部分

    return currFilledSize;
}


#ifdef TEST_MODE
void testDataGenerate(int argc , char * argv[]){
    extern struct paramFlag paramFlag;      // dataGenerator.c 定义的全局变量

    struct strParameter strParam = parameterPasserToStrParam(argc, argv);
    struct numParameter numParam = parseStrParameterToNumParameter(paramFlag, strParam);

    // 需要生成的LOAD长度
    size_t targetLoadLength = getBufferLengthFromGenFrameNum(numParam.numGenFrameNum, numParam.numVCType);

    // LoadLength * splitCols  一个逻辑通道(多个物理通道)下的 一帧Load的空间.
    size_t generateOneColLoadLength = getLoadLengthFromVCType(numParam.numVCType) * numParam.numSplitedCols;
    // 开辟生成连续数据的空间
    // | 00 01 02 03 | 04 05 06 07 | 08 09 10 11 | 12 13 14 15 |
    uint8_t *generateOneColLoadBuffer = malloc(generateOneColLoadLength);
    if (generateOneColLoadBuffer == NULL) {
        printErrorMessage("malloc buffer failed.");
        exit(EXIT_FAILURE);
    }
    fillBlockWithZero(generateOneColLoadBuffer, generateOneColLoadLength);

    // 开辟的文件数据的缓存空间, 总和也是和上面的空间一样大, 这里存储的数据将会是按物理通道离散的.
    size_t outputFileOneColBufferLength = getLoadLengthFromVCType(numParam.numVCType) * numParam.numSplitedCols;
    // | 00 04 08 12 | 01 05 09 13 | 02 06 10 14 | 03 07 11 15 |
    // 必须开辟这部分空间, 因为每次写入一个字节不现实, 方便一次向文件中写入.
    uint8_t *outputFileOneColBuffer = malloc(outputFileOneColBufferLength);
    if (generateOneColLoadBuffer == NULL) {
        printErrorMessage("malloc buffer failed.");
        exit(EXIT_FAILURE);
    }
    fillBlockWithZero(outputFileOneColBuffer, outputFileOneColBufferLength);

    ////////////////////////////////////////////// 数据生成
    if (VERBOSE_FLAG) {
        printInfoMessage("Generating generateData_60a1da8e: ");
    }
    size_t generateBytes = 0;
    size_t continueIndex = 0xfffffff0;
    generateBytes = generateData_00toFF(generateOneColLoadBuffer, generateOneColLoadLength, &continueIndex);
    printBufferDataContent(generateOneColLoadBuffer, generateOneColLoadLength);
    if (VERBOSE_FLAG) {
        printInfoMessage("Continue Generating...");
    }

    fillBlockWithZero(generateOneColLoadBuffer, generateOneColLoadLength);
    generateBytes = generateData_00toFF(generateOneColLoadBuffer, generateOneColLoadLength, &continueIndex);
    printBufferDataContent(generateOneColLoadBuffer, generateOneColLoadLength);

    if (VERBOSE_FLAG) {
        printInfoMessage("Continue Generating...");
    }

    fillBlockWithZero(generateOneColLoadBuffer, generateOneColLoadLength);
    generateBytes = generateData_00toFF(generateOneColLoadBuffer, generateOneColLoadLength, &continueIndex);
    printBufferDataContent(generateOneColLoadBuffer, generateOneColLoadLength);
    if (VERBOSE_FLAG) {
        printInfoMessage("Continue Generating...");
    }

    fillBlockWithZero(generateOneColLoadBuffer, generateOneColLoadLength);
    generateBytes = generateData_00toFF(generateOneColLoadBuffer, generateOneColLoadLength, &continueIndex);
    printBufferDataContent(generateOneColLoadBuffer, generateOneColLoadLength);

    if (VERBOSE_FLAG) {
        printInfoMessage("test Generate complete.");
    }
}

#endif